﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Foothill.Common;
using Foothill.Model;
using Foothill.Service.SystemMessage;

namespace Foothill.Service.AdService
{
    public class PostValidator : IPostValidator
    {
        private ISystemMessageService _systemMessageService;

        private const int mileageMax = 500000;
        private const int priceMax = 5000000;
        
        // constructor
        public PostValidator(ISystemMessageService systemMessageService)
        {
            _systemMessageService = systemMessageService;
        }
        
        // validate an instance of for-sale ad user trying to post
        public bool ValidateForSaleAd(ForSaleAd newAd, out IDictionary<PostForSaleFields, string> invalidFields)
        {
            bool result = true;
            invalidFields = new Dictionary<PostForSaleFields, string>();

            // need to select a valid model  
            if (newAd.ModelId <= 0)
            {
                result = false;
                invalidFields.Add(PostForSaleFields.ModelId, _systemMessageService.GetSystemMessage(SystemMessageCategory.Web, SystemMessageCode.NoModelSelected));
            }

            int convertedInt = 0;

            // price needs to be a non-negative number
            if (ValidatePrice(newAd.PriceStr, out convertedInt))
            {
                newAd.Price = convertedInt;
            }
            else
            {
                // error: price is not non-negative number
                result = false;
                invalidFields.Add(PostForSaleFields.Price, _systemMessageService.GetSystemMessage(SystemMessageCategory.Web, SystemMessageCode.InvalidPriceValue));
            }

            // mileage needs to be a non-negative number
            if (ValidateMileage(newAd.MileAgeStr, out convertedInt))
            {
                newAd.MileAge = convertedInt;
            }
            else
            {
                // error: mile age is not non-negative number
                result = false;
                invalidFields.Add(PostForSaleFields.MileAge, _systemMessageService.GetSystemMessage(SystemMessageCategory.Web, SystemMessageCode.InvalidMileageValue));
            }

            // must be a valid email
            if (!ValidateEmailAddress(newAd.ContactEmail))
            {
                // not a valid email
                result = false;
                invalidFields.Add(PostForSaleFields.ContactEmail, _systemMessageService.GetSystemMessage(SystemMessageCategory.Web, SystemMessageCode.InvalidEmailAddress));
            }

            if (!string.IsNullOrEmpty(newAd.Description))
            {
                if (newAd.Description.Length > GlobalSettings.AdDescriptionMaxNumOfChars)
                {
                    result = false;
                    invalidFields.Add(PostForSaleFields.Description, _systemMessageService.GetSystemMessage(SystemMessageCategory.Web, SystemMessageCode.DescriptionTooLong));
                }
            }

            return result; 
        }

        public bool IsNonNegativeNumber(string str, out int convertedInt32Number)
        {
            if (string.IsNullOrEmpty(str))
            {
                convertedInt32Number = 0;
                return false;
            }

            double tmp;
            if (double.TryParse(str, out tmp))
            {
                if (tmp <= 0)
                {
                    convertedInt32Number = 0;
                    return false;
                }
                else 
                {
                    convertedInt32Number = tmp > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(System.Math.Floor(tmp));
                    return true;
                }
            }
            else
            {
                // not a number
                convertedInt32Number = 0;
                return false;
            }
        }

        public bool ValidateEmailAddress(string str)
        {
            if (string.IsNullOrEmpty(str) || string.IsNullOrWhiteSpace(str))
            {
                return false;
            }
            
            string pattern = @"^[A-Za-z0-9_\-\.]+@(([A-Za-z0-9\-])+\.)+([A-Za-z\-])+$";
            Regex regex = new Regex(pattern);
            return regex.IsMatch(str);
        }

        public bool ValidatePrice(string priceString, out int convertedInt)
        {
            convertedInt = 0;

            if (IsNonNegativeNumber(priceString, out convertedInt))
            {
                convertedInt = convertedInt > priceMax ? priceMax : convertedInt;
                return true;
            }

            return false;
        }

        internal bool ValidateMileage(string mileageString, out int convertedInt)
        {
            convertedInt = 0;

            if (IsNonNegativeNumber(mileageString, out convertedInt))
            {
                convertedInt = convertedInt > mileageMax ? mileageMax : convertedInt;
                return true;
            }
            
            return false;
        }
    }
}
